package com.mrogrape.notepad.ui.editor;

import java.awt.BorderLayout;
import java.awt.Font;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;

import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rtextarea.RTextScrollPane;
import org.fife.ui.rtextarea.SearchContext;
import org.fife.ui.rtextarea.SearchEngine;

import com.mrogrape.notepad.activity.action.MainFrameActionFactory;
import com.mrogrape.notepad.activity.action.item.UpdateSyntaxRendererAction;
import com.mrogrape.notepad.activity.entity.ViewSettings;
import com.mrogrape.notepad.common.ViewUtils;
import com.mrogrape.notepad.data.ApplicationContext;
import com.mrogrape.notepad.data.SystemContext;
import com.mrogrape.notepad.data.ViewContext;
import com.mrogrape.notepad.resource.Settings;
import com.mrogrape.notepad.resource.Strings;
import com.mrogrape.notepad.ui.ClosableTabPanel;
import com.mrogrape.notepad.ui.ClosableTabbedPane;
import com.mrogrape.notepad.ui.filechooser.SaveOption;
import com.mrogrape.util.StringUtils;

public class TextEditor extends ClosableTabPanel {

	/** 属性：字符集 */
	public static final String PROPERTY_CHARSET = "charset";
	/** 属性：可编辑 */
	public static final String PROPERTY_EDITABLE = "editable";

	/** serialVersionUID */
	private static final long serialVersionUID = 1L;

	/** 允许读取的最大文件长度：10M */
	private static final long ALLOWED_MAX_FILE_LENGTH = 10485760;

	/**
	 * 创建空白文本编辑器并指定内容类型。
	 * 
	 * @param contentType
	 *            文本类型
	 * @param parent
	 *            所属容器
	 */
	public TextEditor(ContentType contentType, ClosableTabbedPane parent) {

		this(contentType, null, null, null, parent);
	}

	/**
	 * 创建空白文本编辑器并指定内容类型。
	 * 
	 * @param contentType
	 *            文本类型
	 * @param parent
	 *            所属容器
	 */
	public TextEditor(ContentType contentType, String title, ClosableTabbedPane parent) {

		this(contentType, null, null, title, parent);
	}

	/**
	 * 创建文本编辑器并从指定文件以默认字符集读取文本。
	 * 
	 * @param file
	 *            指定的文件
	 * @param parent
	 *            容器
	 */
	public TextEditor(File file, ClosableTabbedPane parent) {
		this(ContentType.PLAIN_TEXT, file, null, null, parent);
	}

	/**
	 * 创建文本编辑器并从指定文件以指定字符集读取文本。
	 * 
	 * @param file
	 *            指定的文件
	 * @param charset
	 *            字符集
	 * @param parent
	 *            容器
	 */
	public TextEditor(File file, String charset, ClosableTabbedPane parent) {
		this(ContentType.PLAIN_TEXT, file, charset, null, parent);
	}

	private TextEditor(ContentType contentType, File file, String charset, String title, ClosableTabbedPane parent) {

		this.contentType = contentType;
		this.file = file;
		this.charset = charset;
		this.defaultTitle = title;
		this.parent = parent;
		this.viewSettings = Settings.getSettings().getViewSettings();

		this.initializeComponents();
		this.prepare();

	}

	/**
	 * 创建保存选项
	 * 
	 * @return
	 */
	public SaveOption createSaveOption() {
		SaveOption option = new SaveOption();

		option.setCharset(this.charset);
		option.setFile(this.file);
		return option;
	}

	@Override
	public boolean onClose() {

		if ((this.file == null && StringUtils.isNotEmpty(this.getText()))
				|| (this.file != null && this.isContentModified())) {

			int re = ViewUtils.showYesNoCancelDialog(this, "Alert", "The editor \"" + this.getPlainTitle()
					+ "\" has unsaved changes, Save changes?");

			switch (re) {

			case ViewUtils.CANCEL_OPTION:
				return false;
			case ViewUtils.YES_OPTION:

				if (this.file == null) {

				}
				this.saveFile();
			case ViewUtils.NO_OPTION:
				return true;
			}
		}

		return true;
	}

	/**
	 * 更改内容高亮渲染模式。
	 * 
	 * @param styleKey
	 */
	public void setSyntaxRendererStyle(String styleKey) {

		this.editor.setSyntaxEditingStyle(styleKey);
	}

	/**
	 * 获取内容高亮渲染模式。
	 * 
	 * @return
	 */
	public String getSyntaxRenderStyle() {

		return this.editor.getSyntaxEditingStyle();
	}

	/**
	 * 获取内容类型
	 * 
	 * @return
	 */
	public ContentType getContentType() {

		return this.contentType;
	}

	/**
	 * 设置内容类型
	 * 
	 * @param contentType
	 */
	public void setContentType(ContentType contentType) {

		this.contentType = contentType;
		this.updateSyntaxRenderer();
	}

	/**
	 * 获取选中的文本。
	 * 
	 * @return
	 */
	public String getSelectedText() {

		return this.editor.getSelectedText();
	}

	@Override
	public String getViewableTitle() {

		String title = this.getPlainTitle();

		if (this.isContentModified) {
			title = "*" + title;
		}

		return title;
	}

	/**
	 * 获取不带修饰的标题。
	 * 
	 * @return
	 */
	public String getPlainTitle() {

		String title = null;
		if (this.file == null) {
			if (StringUtils.isEmpty(this.defaultTitle)) {
				title = "Untitled-" + ApplicationContext.nextTabTitleSequenceNo() + "."
						+ this.contentType.getPreferredFileExtension();
				this.defaultTitle = title;
			} else {
				title = this.defaultTitle;
			}
		} else {

			title = this.file.getName();
		}

		return title;
	}

	/**
	 * 获取此编辑器当前正在编辑的文件，如果还未指定，则返回null。
	 * 
	 * @return
	 */
	public File getFile() {

		return this.file;
	}

	/**
	 * 设置编辑器文件。
	 * 
	 * @param file
	 * @param isReload
	 *            是否重新加载
	 */
	public void setFile(File file, boolean isReload) {

		this.file = file;
		this.notifyContainerTitleChanged();

		if (isReload) {
			this.loadFile();
		}
	}

	/**
	 * 获取编辑器字体。
	 * 
	 * @return
	 */
	public Font getEditorFont() {

		return this.editor.getFont();
	}

	/**
	 * 设置编辑器字体。
	 * 
	 * @param font
	 */
	public void setEditorFont(Font font) {

		this.editor.setFont(font);
	}

	/**
	 * 查看文件是否存在。
	 * 
	 * @return
	 */
	public boolean isFileExist() {

		return this.file != null && this.file.exists();
	}

	/**
	 * 查看文件是否为只读
	 * 
	 * @return
	 */
	public boolean isReadOnly() {

		if (this.file == null || !this.file.exists()) {
			return false;
		}

		return !this.file.canWrite();
	}

	/**
	 * 设置文件为只读。
	 * 
	 * @return
	 */
	public boolean setReadOnly(boolean isReadOnly) {

		if (this.file == null || this.isContentModified) {

			return false;
		}

		if (isReadOnly) {

			if (!this.file.canWrite()) {

				this.setEditable(false);
				return true;
			}

			boolean result = this.file.setReadOnly();

			if (result) {
				this.setEditable(false);
				return true;
			}

			return false;

		} else {

			if (!this.file.canWrite()) {

				boolean result = this.file.setWritable(true);

				if (result) {
					this.setEditable(true);
					return true;
				}

				return false;

			}

			this.setEditable(true);
			return true;
		}
	}

	/**
	 * 设置编辑器的可编辑状态
	 * 
	 * @param editable
	 */
	public void setEditable(boolean editable) {

		boolean oldValue = this.editor.isEditable();
		super.firePropertyChange(TextEditor.PROPERTY_EDITABLE, oldValue, editable);
		this.editor.setEditable(editable);
	}

	/**
	 * 获取编辑器的可编辑状态。
	 * 
	 * @return
	 */
	public boolean isEditable() {
		return this.editor.isEditable();
	}

	/**
	 * 获取文件编码。
	 * 
	 * @return
	 */
	public String getCharset() {

		if (this.charset == null) {
			this.charset = ApplicationContext.getSystemDefaultTextCharset();
		}

		return this.charset;
	}

	/**
	 * 设置编辑器文本编码。
	 * 
	 * @param charset
	 */
	public void setCharset(String charset) {

		String oldValue = this.charset;
		super.firePropertyChange(TextEditor.PROPERTY_CHARSET, oldValue, charset);

		this.charset = charset;
	}

	/**
	 * 设置文档的换行符。
	 * 
	 * @param ls
	 */
	public void setLineSeparaotr(String ls){
		this.lineSeparator = ls;
	}

	/**
	 * 获取文档的换行符。
	 * 
	 * @return
	 */
	public String getLineSeparator(){
		return this.lineSeparator;
	}
	
	/**
	 * 获取编辑器文本
	 * 
	 * @return
	 */
	public String getText() {

		return this.editor.getText();
	}

	/**
	 * 设置编辑器文本。
	 * 
	 * @param text
	 */
	public void setText(String text) {

		this.editor.setText(text);
	}

	/**
	 * 指示内容是否在上次保存后被更改。
	 * 
	 * @return
	 */
	public boolean isContentModified() {

		return this.isContentModified;
	}

	/**
	 * 指示文件自打开过是否被更改。
	 * 
	 * @return
	 */
	public boolean isFileChanged() {

		return this.isFileChanged;
	}

	/**
	 * 查找内容，如果找到内容则选中并返回true，反正返回false且不执行任何操作。
	 * 
	 * @param context
	 *            搜索选项
	 * @param wrapSearch
	 *            是否循环查找，如果为true，则如果从当前位置查找不到则将光标 返回文档开始再次尝试查找。
	 */
	public boolean find(SearchContext context, boolean wrapSearch) {

		boolean isFound = SearchEngine.find(this.editor, context);

		if (!isFound && wrapSearch) {

			String searchFor = context.getSearchFor();
			if (context.isRegularExpression()) {
				Pattern pattern = null;
				if (context.getMatchCase()) {
					pattern = Pattern.compile(searchFor);
				} else {
					pattern = Pattern.compile(searchFor, Pattern.CASE_INSENSITIVE);
				}

				Matcher matcher = pattern.matcher(this.getText());
				if (matcher.find()) {

					this.editor.setCaretPosition(context.getSearchForward() ? 0 : (this.getText().length()));
					return SearchEngine.find(this.editor, context);
				} else {

					return false;
				}
			} else {

				if (context.getMatchCase() && this.editor.getText().contains(searchFor)) {

					this.editor.setCaretPosition(context.getSearchForward() ? 0 : (this.getText().length()));
					return SearchEngine.find(this.editor, context);
				} else if (!context.getMatchCase()
						&& this.editor.getText().toLowerCase().contains(searchFor.toLowerCase())) {

					this.editor.setCaretPosition(context.getSearchForward() ? 0 : (this.getText().length()));
					return SearchEngine.find(this.editor, context);
				} else {

					return false;
				}
			}
		}

		return isFound;
	}

	/**
	 * 替换内容
	 * 
	 * @param context
	 *            搜索选项
	 * @return 是否成功替换
	 */
	public boolean replace(SearchContext context) {

		return SearchEngine.replace(this.editor, context);
	}

	public void replaceAll(SearchContext context) {

		SearchEngine.replaceAll(this.editor, context);
	}

	/**
	 * 加载文件
	 */
	public void loadFile() {

		if (this.file != null && this.file.exists()) {

			if (this.file.length() > TextEditor.ALLOWED_MAX_FILE_LENGTH) {
				this.file = null;
				ViewUtils.showErrorMessageDialog(this, Strings.Message.FILE_TOO_BIG);
			} else {
				this.editor.setText(Strings.Message.READING);
				TextEditor.this.readFile();
			}
		}
	}

	/**
	 * 保存文件
	 */
	public void saveFile() {

		if (this.file == null) {

			return;
		}
		
		if (this.isReadOnly()){
			ViewUtils.showErrorMessageDialog(this, "\"" + this.getFile() + "\"是只读的，如果这不是您的操作，那么它可能是被外部的软件所更改。");
			return;
		}

		try {
			com.mrogrape.io.TextIO.writeText(this.getText(), this.lineSeparator, this.file, this.charset);
			this.setContentModified(false);
			this.setFileChanged(true);

			// 添加至最近使用的文件、
			ViewContext.getRecentFileMenu().loadOrSaveFile(this.file);
		} catch (FileNotFoundException e) {
			ViewUtils.showErrorMessageDialog(this, "\"" + this.getFile() + "\"目标路径不可用。");
		} catch (UnsupportedEncodingException e) {
			ViewUtils.showErrorMessageDialog(this, "\"" + this.getCharset() + "\"字符集不被支持。");
		} catch (IOException e) {
			ViewUtils.showErrorMessageDialog(this, "保存文件时出现了未知的I/O异常，消息：" + e.getMessage());
		} 
	}

	/**
	 * 撤销最后的编辑
	 */
	public void undo() {

		this.editor.undoLastAction();
	}

	/**
	 * 查看是否可以执行撤销操作。
	 * 
	 * @return
	 */
	public boolean canUndo() {

		return this.editor.canUndo();
	}

	/**
	 * 查看是否可以执行重做操作。
	 * 
	 * @return
	 */
	public boolean canRedo() {

		return this.editor.canRedo();
	}

	/**
	 * 重做最后一次编辑（一般发生在撤销之后）
	 */
	public void redo() {

		this.editor.redoLastAction();
	}

	/**
	 * 复制
	 */
	public void copy() {

		this.editor.copy();
	}

	/**
	 * 复制内容和格式（RTF形式）
	 */
	public void copyAsRtf() {

		this.editor.copyAsRtf();
	}

	/**
	 * 剪切
	 */
	public void cut() {

		this.editor.cut();
	}

	/**
	 * 粘贴
	 */
	public void paste() {

		this.editor.paste();
	}

	/**
	 * 删除选中的内容。
	 */
	public void delete() {

		if (this.editor.isEditable() && this.editor.isEnabled()) {
			this.editor.replaceSelection("");
		}
	}

	/**
	 * 清除内容,
	 */
	public void clear() {

		if (this.editor.isEnabled() && this.editor.isEditable()) {
			this.editor.setText("");
		}
	}

	/**
	 * 选中全部内容
	 */
	public void selectAll() {

		this.editor.selectAll();
	}

	/**
	 * 删除选中的文本，如果没有选中文本则不执行任何操作
	 */
	public void deleteSelection() {

		this.editor.replaceSelection("");
	}

	/**
	 * 替换选中的文本。
	 * 
	 * @param text
	 */
	public void replaceSelection(String text) {

		this.editor.replaceSelection(text);
	}

	/**
	 * 在文档末尾添加文本
	 * 
	 * @param text
	 */
	public void append(String text) {

		this.editor.append(text);
	}

	/**
	 * 在文档末尾添加文本并换行
	 * 
	 * @param text
	 */
	public void appendLine(String text) {

		this.editor.append(text);
		this.editor.append(StringUtils.LINE_SEPARATOR);
	}

	/**
	 * 在光标处插入文本。
	 * 
	 * @param text
	 */
	public void insert(String text) {

		this.insert(text, this.editor.getCaretPosition());

	}

	/**
	 * 在指定位置插入文本
	 * 
	 * @param text
	 * @param pos
	 */
	public void insert(String text, int pos) {

		if (this.editor.isEnabled() && this.editor.isEditable()) {
			this.editor.insert(text, pos);
		}
	}

	/**
	 * 添加一个文档监听器。
	 * 
	 * @param l
	 */
	public void addDoucumentListener(DocumentListener l) {

		this.editor.getDocument().addDocumentListener(l);
	}

	/**
	 * 移除一个文档监听器。
	 * 
	 * @param l
	 */
	public void removeDocumentListener(DocumentListener l) {

		this.editor.getDocument().removeDocumentListener(l);
	}

	/**
	 * 添加一个光标监听器。
	 * 
	 * @param l
	 */
	public void addCaretListener(CaretListener l) {

		this.editor.addCaretListener(l);
	}

	/**
	 * 移除一个光标监听器。
	 * 
	 * @param l
	 */
	public void removeCaretListener(CaretListener l) {

		this.editor.removeCaretListener(l);
	}

	/**
	 * 获取光标所在行号。
	 * 
	 * @return
	 */
	public int getCaretLineNumber() {

		return this.editor.getCaretLineNumber();
	}

	/**
	 * 获取光标所在位置距离当前行首的偏移量。
	 * 
	 * @return
	 */
	public int getCaretOffsetFromLineStart() {

		return this.editor.getCaretOffsetFromLineStart();
	}

	/**
	 * 开始一个自动编辑的过程，在此期间所有的编辑都将视为一次编辑。
	 */
	public void beginAtomicEdit(){
		
		this.editor.beginAtomicEdit();
	}
	
	/**
	 * 停止自动编辑的过程。
	 */
	public void endAtomicEdit(){
		
		this.editor.endAtomicEdit();
	}
	
	/**
	 * 设置是否显示行号。
	 * 
	 * @param aFlg
	 */
	public void setLineNumberVisible(boolean aFlg) {

		this.scrollPane.setLineNumbersEnabled(aFlg);
	}

	/**
	 * 查看行号是否显示。
	 * 
	 * @return
	 */
	public boolean isLineNumberVisible() {

		return this.scrollPane.getLineNumbersEnabled();
	}

	public boolean isLineWrap() {
		return this.editor.getLineWrap();
	}

	public void setLineWrap(boolean lineWrap) {
		this.editor.setLineWrap(lineWrap);
	}

	public boolean isWhiteSpaceVisible() {
		return this.editor.isWhitespaceVisible();
	}

	public void setWhiteSpaceVisible(boolean whiteSpaceVisible) {
		this.editor.setWhitespaceVisible(whiteSpaceVisible);
	}

	public boolean isEOLMarkVisible() {
		return this.editor.getEOLMarkersVisible();
	}

	public void setEOLMarkVisible(boolean eofMarkVisible) {
		this.editor.setEOLMarkersVisible(eofMarkVisible);
	}

	public boolean isHeightLightSecondaryLanguage() {
		return this.editor.getHighlightSecondaryLanguages();
	}

	public void setHeightLightSecondaryLanguage(boolean heightLightSecondaryLanguage) {
		this.editor.setHighlightSecondaryLanguages(heightLightSecondaryLanguage);
	}

	public boolean isMarkOccurrences() {
		return this.editor.getMarkOccurrences();
	}

	public void setMarkOccurrences(boolean markOccurrences) {
		this.editor.setMarkOccurrences(markOccurrences);
	}

	public boolean isCodeFoldingEnabled() {
		return this.editor.isCodeFoldingEnabled();
	}

	public void setCodeFoldingEnabled(boolean codeFoldingEnabled) {
		this.editor.setCodeFoldingEnabled(codeFoldingEnabled);
	}

	public boolean isHyperlinksEnabled() {
		return this.editor.getHyperlinksEnabled();
	}

	public void setHyperlinksEnabled(boolean hyperlinksEnabled) {
		this.editor.setHyperlinksEnabled(hyperlinksEnabled);
	}

	public boolean isAutoIndentEnabled() {
		return this.editor.isAutoIndentEnabled();
	}

	public void setAutoIndentEnabled(boolean autoIndentEnabled) {
		this.editor.setAutoIndentEnabled(autoIndentEnabled);
	}

	public boolean isCloseCurlyBraces() {
		return this.editor.getCloseCurlyBraces();
	}

	public void setCloseCurlyBraces(boolean closeCurlyBraces) {
		this.editor.setCloseCurlyBraces(closeCurlyBraces);
	}

	public boolean isCloseMarkupTags() {
		return this.editor.getCloseMarkupTags();
	}

	public void setCloseMarkupTags(boolean closeMarkupTags) {
		this.editor.setCloseMarkupTags(closeMarkupTags);
	}
	
	public int getSelectionStart(){
		
		return this.editor.getSelectionStart();
	}
	
	public int getSelectionEnd(){
		
		return this.editor.getSelectionEnd();
	}
	
	public int getLineOfOffset(int offs) throws BadLocationException{
		
		return this.editor.getLineOfOffset(offs);
	}
	
	public String getTextOfLine(int line) throws BadLocationException{
		int start = this.editor.getLineStartOffset(line);
		int end = this.editor.getLineEndOffset(line);
		
		return this.editor.getText().substring(start, end);
	}
	
	/**
	 * replace the specified line to text, that will contains the end-of-line separator
	 * 
	 * @param line
	 * @param text
	 * @throws BadLocationException 
	 */
	public void replaceLine(int line, String text) throws BadLocationException{

		int start = this.editor.getLineStartOffset(line);
		int end = this.editor.getLineEndOffset(line);
		
		this.editor.replaceRange(text, start, end);
	}
	
	/**
	 * 返回当前编辑器文本的行数。
	 * 
	 * @return 当前编辑器文本的行数。
	 */
	public int getLineCount(){
		
		return this.editor.getLineCount();
	}
	
	/**
	 * 设置光标的位置到某一行。
	 * 
	 * @param line
	 * @throws BadLocationException
	 */
	public void setCaretPositionByLine(int line) throws BadLocationException{
		
		int offs = this.editor.getLineStartOffset(line);
		this.editor.setCaretPosition(offs);
	}
	
	/**
	 * 通知此编辑器的容器标题更改。
	 */
	private void notifyContainerTitleChanged() {

		this.parent.updateComponentTitle(this);
	}

	private void initializeComponents() {

		this.setLayout(new BorderLayout());

		this.editor = new RSyntaxTextArea();
		this.scrollPane = new RTextScrollPane(this.editor);
		this.add(this.scrollPane);
		
		// TODO FOR TEMP USING
//		InputStream in = getClass().getResourceAsStream("/com/mrogrape/notepad/dark.xml");
//		try {
//			Theme theme = Theme.load(in);
//			theme.apply(this.editor);
//		} catch (IOException e) {
//			
//			e.printStackTrace();
//		}
		// TODO END

		// 字体
		Font font = Settings.getSettings().getEditorFont();
		this.editor.setFont(ViewUtils.createNewFont(font.getFamily(), font.getStyle(), font.getSize()));
		// 更新内容渲染器
		this.updateSyntaxRenderer();

		// 行号是否显示
		this.scrollPane.setLineNumbersEnabled(this.viewSettings.isLineNumberVisible());

		// 自动换行
		this.editor.setLineWrap(this.viewSettings.isLineWrap());
		// 显示空白字符
		this.editor.setWhitespaceVisible(this.viewSettings.isWhiteSpaceVisible());
		// 显示EOL字符
		this.editor.setEOLMarkersVisible(this.viewSettings.isEOLMarkVisible());
		// 高亮第二语言
		this.editor.setHighlightSecondaryLanguages(this.viewSettings.isHeightLightSecondaryLanguage());
		// 标记出现位置
		this.editor.setMarkOccurrences(this.viewSettings.isMarkOccurrences());
		// 代码折叠
		this.editor.setCodeFoldingEnabled(this.viewSettings.isCodeFoldingEnabled());
		// 超级链接
		this.editor.setHyperlinksEnabled(this.viewSettings.isHyperlinksEnabled());
		// 自动缩进
		this.editor.setAutoIndentEnabled(this.viewSettings.isAutoIndentEnabled());
		// 自动关闭大括号
		this.editor.setCloseCurlyBraces(this.viewSettings.isCloseCurlyBraces());
		// 自动关闭匹配标签
		this.editor.setCloseMarkupTags(this.viewSettings.isCloseMarkupTags());

		// 添加内容变更监听器
		this.editor.getDocument().addDocumentListener(new DefaultDocumentListener());
		
		this.buildPopupMenu();
	}

	private void buildPopupMenu() {

		JPopupMenu pop = this.editor.getPopupMenu();
		pop.add(new JMenuItem(new UpdateSyntaxRendererAction()));
		pop.add(MainFrameActionFactory.fetchOpenFileLocationMenuItemAction());
		pop.add(MainFrameActionFactory.fetchTrimEndOfLineMenuItemAction());
		pop.add(MainFrameActionFactory.fetchFixLineToMaxMenuItemAction());
	}

	private void prepare() {

		// 加载文件
		this.loadFile();
	}

	/**
	 * 读取文件的方法。
	 */
	private void readFile() {

		// 获取字符集
		try {
			if (this.charset == null) {
				this.charset = ApplicationContext.getSystemDefaultTextCharset();
			}
		} catch (Exception e) {

			ViewUtils.showErrorMessageDialog(this, "Error to sniff charset.");
			return;
		}

		this.setEditable(false);

		// 读取文件。
		try {
			InputStream is = new FileInputStream(this.file);
			InputStreamReader reader = new InputStreamReader(is, this.charset);

			this.editor.read(reader, this.file);
			reader.close();

			// USING THE METHOD OF TEXTIO TO READ TEXT
			// String text=TextIO.read(is,this.charset,0,Integer.MAX_VALUE);
			// this.editor.setText(text);
			this.setContentModified(false);
			this.setFileChanged(false);
			this.updateSyntaxEditingStyleFomeFile();

			// 添加至最近使用的文件、
			ViewContext.getRecentFileMenu().loadOrSaveFile(this.file);
		} catch (IOException e) {

			ViewUtils.showErrorMessageDialog(this,
					Strings.getFixedString(Strings.Message.CANNOT_READ_FILE, e.getMessage()));
			this.editor.setText(StringUtils.BLANK);
		}

		if (!this.isReadOnly()) {
			this.setEditable(true);
		}
	}

	/**
	 * 设置编辑器内容是否被改变
	 * 
	 * @param isModified
	 */
	private void setContentModified(boolean isModified) {

		this.isContentModified = isModified;
		this.notifyContainerTitleChanged();
	}

	/**
     *
     */
	private void setFileChanged(boolean isChanged) {

		this.isFileChanged = isChanged;
	}

	/**
	 * 从文件更新语法高亮渲染器。
	 */
	private void updateSyntaxEditingStyleFomeFile() {

		if (this.file != null) {
			this.contentType = ApplicationContext.findContentTypeFromFileExtension(this.file);
		}

		// 更新渲染器。
		this.updateSyntaxRenderer();
	}

	/**
	 * 根据内容类型更新语法高亮渲染器。
	 */
	private void updateSyntaxRenderer() {

		this.editor.setSyntaxEditingStyle(this.contentType.getMimeType());
	}

	/**
	 * 文本变更事件处理器。
	 * 
	 * @author IceSpring
	 * 
	 */
	private class DefaultDocumentListener implements DocumentListener {

		@Override
		public void changedUpdate(DocumentEvent e) {
		}

		@Override
		public void insertUpdate(DocumentEvent e) {

			this.textChanged(e);
		}

		@Override
		public void removeUpdate(DocumentEvent e) {

			this.textChanged(e);
		}

		private void textChanged(DocumentEvent e) {

			if (!TextEditor.this.isContentModified) {
				TextEditor.this.setContentModified(true);
			}
		}

	}

	private File file = null;

	private String defaultTitle = null;
	private ContentType contentType = ContentType.PLAIN_TEXT;
	private boolean isContentModified = false;
	private boolean isFileChanged = false;
	private String charset = null;
	private String lineSeparator = SystemContext.getSystemLineSeparator();

	private ClosableTabbedPane parent = null;
	private RTextScrollPane scrollPane = null;
	private RSyntaxTextArea editor = null;

	private ViewSettings viewSettings = null;
}
